package com.iotcomm.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iotcomm.listener.MessageListener;
import com.iotcomm.protocol.Message;
import com.iotcomm.protocol.MessageCodec;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import javafx.application.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * 聊天客户端主类
 * 负责连接服务器，发送和接收消息
 */
public class ChatClient implements MessageListener {
    private static final Logger logger = LoggerFactory.getLogger(ChatClient.class);
    
    private EventLoopGroup group;
    private ClientHandler clientHandler;
    private String username;
    private boolean connected = false;
    
    // 心跳机制
    private final ScheduledExecutorService heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
    private static final int HEARTBEAT_INTERVAL = 10; // 10秒发送一次心跳
    
    // JSON处理器（用于用户列表解析）
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    // 回调函数
    private Consumer<String> connectionStatusCallback;
    private Consumer<Message> messageReceivedCallback;
    private Consumer<List<String>> userListUpdateCallback;
    private Consumer<String> errorCallback;
    
    /**
     * 连接到服务器
     * @param host 服务器地址
     * @param port 服务器端口
     * @param username 用户名
     */
    public void connect(String host, int port, String username) {
        this.username = username;
        
        group = new NioEventLoopGroup();
        clientHandler = new ClientHandler(this);
        
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 添加消息编解码器
                            pipeline.addLast(new MessageCodec());
                            // 添加业务处理器
                            pipeline.addLast(clientHandler);
                        }
                    });
            
            // 连接服务器
            ChannelFuture future = bootstrap.connect(host, port).sync();
            
            if (future.isSuccess()) {
                logger.info("连接服务器成功: {}:{}", host, port);
                connected = true;
                updateConnectionStatus("已连接到服务器");
                
                // 发送登录请求
                sendLoginRequest();
                
                // 启动心跳
                startHeartbeat();
                
            } else {
                logger.error("连接服务器失败: {}:{}", host, port);
                updateConnectionStatus("连接失败");
                disconnect();
            }
            
        } catch (Exception e) {
            logger.error("连接服务器时发生错误", e);
            updateConnectionStatus("连接错误: " + e.getMessage());
            updateError("连接失败: " + e.getMessage());
            disconnect();
        }
    }
    
    /**
     * 断开连接
     */
    public void disconnect() {
        try {
            connected = false;
            
            // 停止心跳
            heartbeatExecutor.shutdown();
            
            // 发送登出消息
            if (clientHandler != null && clientHandler.isConnected()) {
                Message logoutMsg = new Message(Message.LOGOUT, username, null, "");
                clientHandler.sendMessage(logoutMsg);
            }
            
            // 关闭连接
            if (clientHandler != null) {
                clientHandler.disconnect();
            }
            
            // 关闭事件循环组
            if (group != null) {
                group.shutdownGracefully();
            }
            
            logger.info("已断开与服务器的连接");
            updateConnectionStatus("已断开连接");
            
        } catch (Exception e) {
            logger.error("断开连接时发生错误", e);
        }
    }
    
    /**
     * 发送登录请求
     */
    private void sendLoginRequest() {
        Message loginMsg = Message.createLogin(username);
        clientHandler.sendMessage(loginMsg);
        logger.info("发送登录请求: {}", username);
    }
    
    /**
     * 启动心跳机制
     */
    private void startHeartbeat() {
        if (!heartbeatExecutor.isShutdown()){
            heartbeatExecutor.scheduleAtFixedRate(() -> {
                if (connected && clientHandler != null && clientHandler.isConnected()) {
                    Message heartbeat = Message.createHeartbeat(username);
                    clientHandler.sendMessage(heartbeat);
                    logger.debug("发送心跳包");
                }
            }, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
        }
    }
    
    /**
     * 发送私聊消息
     * @param receiver 接收者
     * @param content 消息内容
     */
    public void sendPrivateMessage(String receiver, String content) {
        if (!connected || clientHandler == null) {
            updateError("未连接到服务器");
            return;
        }
        
        Message message = Message.createPrivateChat(username, receiver, content);
        clientHandler.sendMessage(message);
        

        
        logger.info("发送私聊消息: {} -> {}", username, receiver);
    }
    
    /**
     * 发送广播消息
     * @param content 消息内容
     */
    public void sendBroadcastMessage(String content) {
        if (!connected || clientHandler == null) {
            updateError("未连接到服务器");
            return;
        }
        
        Message message = Message.createBroadcast(username, content);
        clientHandler.sendMessage(message);
        
        logger.info("发送广播消息: {}", username);
    }
    

    
    @Override
    public void onMessageReceived(Message message, String channelId) {
        try {
            switch (message.getMessageType()) {
                case Message.LOGIN_RESPONSE:
                    handleLoginResponse(message);
                    break;
                case Message.PRIVATE_CHAT:
                    handlePrivateChat(message);
                    break;
                case Message.BROADCAST:
                    handleBroadcast(message);
                    break;
                case Message.USER_LIST:
                    handleUserList(message);
                    break;
                case Message.ERROR:
                    handleError(message);
                    break;
                case Message.HEARTBEAT:
                    // 心跳响应，无需特殊处理
                    logger.debug("收到心跳响应");
                    break;
                default:
                    logger.warn("未知消息类型: {}", message.getMessageType());
            }
        } catch (Exception e) {
            logger.error("处理接收消息时发生错误", e);
        }
    }
    
    /**
     * 处理登录响应
     */
    private void handleLoginResponse(Message message) {
        if ("登录成功".equals(message.getContent())) {
            logger.info("登录成功");
            updateConnectionStatus("已登录");
        } else {
            logger.error("登录失败: {}", message.getContent());
            updateError("登录失败: " + message.getContent());
            disconnect();
        }
    }
    
    /**
     * 处理私聊消息
     */
    private void handlePrivateChat(Message message) {

        
        // 通知UI
        updateMessageReceived(message);
        
        logger.info("收到私聊消息: {} -> {}", message.getSender(), message.getReceiver());
    }
    
    /**
     * 处理广播消息
     */
    private void handleBroadcast(Message message) {
        // 通知UI
        updateMessageReceived(message);
        
        logger.info("收到广播消息: {}", message.getSender());
    }
    
    /**
     * 处理用户列表更新
     */
    private void handleUserList(Message message) {
        try {
            List<String> userList = objectMapper.readValue(message.getContent(), new TypeReference<>()
            {
            });
            updateUserList(userList);
            logger.debug("用户列表更新: {} 个用户", userList.size());
        } catch (Exception e) {
            logger.error("解析用户列表失败", e);
        }
    }
    
    /**
     * 处理错误消息
     */
    private void handleError(Message message) {
        updateError(message.getContent());
        logger.error("服务器错误: {}", message.getContent());
    }
    
    @Override
    public void onClientConnected(String channelId) {
        logger.debug("客户端连接事件: {}", channelId);
    }
    
    @Override
    public void onClientDisconnected(String channelId, String username) {
        connected = false;
        updateConnectionStatus("连接已断开");
        logger.info("与服务器断开连接");
    }
    
    @Override
    public void onConnectionError(String channelId, Throwable cause) {
        connected = false;
        updateConnectionStatus("连接错误");
        updateError("连接错误: " + cause.getMessage());
        logger.error("连接错误", cause);
    }
    
    // 更新UI的辅助方法
    private void updateConnectionStatus(String status) {
        if (connectionStatusCallback != null) {
            Platform.runLater(() -> connectionStatusCallback.accept(status));
        }
    }
    
    private void updateMessageReceived(Message message) {
        if (messageReceivedCallback != null) {
            Platform.runLater(() -> messageReceivedCallback.accept(message));
        }
    }
    
    private void updateUserList(List<String> userList) {
        if (userListUpdateCallback != null) {
            Platform.runLater(() -> userListUpdateCallback.accept(userList));
        }
    }
    
    private void updateError(String error) {
        if (errorCallback != null) {
            Platform.runLater(() -> errorCallback.accept(error));
        }
    }
    
    // Getter和Setter方法
    public boolean isConnected() {
        return connected;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setConnectionStatusCallback(Consumer<String> callback) {
        this.connectionStatusCallback = callback;
    }
    
    public void setMessageReceivedCallback(Consumer<Message> callback) {
        this.messageReceivedCallback = callback;
    }
    
    public void setUserListUpdateCallback(Consumer<List<String>> callback) {
        this.userListUpdateCallback = callback;
    }
    
    public void setErrorCallback(Consumer<String> callback) {
        this.errorCallback = callback;
    }
}